QLibrary: fix deadlock caused by fix to QTBUG-39642
authorDebian Qt/KDE Maintainers <debian-qt-kde@lists.debian.org>
Fri, 26 Jun 2020 16:47:18 +0000 (17:47 +0100)
committerDmitry Shachnev <mitya57@debian.org>
Fri, 26 Jun 2020 16:47:18 +0000 (17:47 +0100)
Origin: upstream, https://code.qt.io/cgit/qt/qtbase.git/commit/?id=276fa8383a753576
Last-Update: 2020-04-17

Commit ae6f73e8566fa76470937aca737141183929a5ec inserted a mutex around
the entire load_sys(). We had reasoned that deadlocks would only occur if
the object creation in instance() recursed into its own instance(),
which was already a bug. But we had forgotten that dlopen()/
LoadLibrary() executes initialization code from the module being loaded,
which could cause a recursion back into the same QPluginLoader or
QLibrary object. This recursion is benign because the module *is* loaded
and dlopen()/LoadLibrary() returns the same handle.

Gbp-Pq: Name fix_qlibrary_deadlock.diff

src/corelib/plugin/qlibrary.cpp
src/corelib/plugin/qlibrary_unix.cpp
src/corelib/plugin/qlibrary_win.cpp

index ddb053c26faeb8544204f8f333d8d5a37af724f6..be9d92b2048dae01dc762b83db589eac4e3eec9e 100644 (file)
@@ -576,9 +576,7 @@ bool QLibraryPrivate::load()
 
     Q_TRACE(QLibraryPrivate_load_entry, fileName);
 
-    mutex.lock();
     bool ret = load_sys();
-    mutex.unlock();
     if (qt_debug_component()) {
         if (ret) {
             qDebug() << "loaded library" << fileName;
index 29813e5863b30ff7034f03e3f049eae2c5c13837..127321b5d08de85c3f8fbbec205210c9363006ba 100644 (file)
@@ -123,6 +123,7 @@ QStringList QLibraryPrivate::prefixes_sys()
 
 bool QLibraryPrivate::load_sys()
 {
+    QMutexLocker locker(&mutex);
     QString attempt;
     QFileSystemEntry fsEntry(fileName);
 
@@ -213,6 +214,7 @@ bool QLibraryPrivate::load_sys()
     }
 #endif
 
+    locker.unlock();
     bool retry = true;
     Handle hnd = nullptr;
     for (int prefix = 0; retry && !hnd && prefix < prefixes.size(); prefix++) {
@@ -273,6 +275,8 @@ bool QLibraryPrivate::load_sys()
         }
     }
 #endif
+
+    locker.relock();
     if (!hnd) {
         errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName, qdlerror());
     }
index 000bf76276396b9873fb3003de81dc208247dcfc..ef58724be8e9b5364a6fd35947a9e78c52d7e7fc 100644 (file)
@@ -78,6 +78,7 @@ bool QLibraryPrivate::load_sys()
     //     fileName
     //
     // NB If it's a plugin we do not ever try the ".dll" extension
+    QMutexLocker locker(&mutex);
     QStringList attempts;
 
     if (pluginState != IsAPlugin)
@@ -95,6 +96,7 @@ bool QLibraryPrivate::load_sys()
         attempts.prepend(QDir::rootPath() + fileName);
 #endif
 
+    locker.unlock();
     Handle hnd = nullptr;
     for (const QString &attempt : qAsConst(attempts)) {
 #ifndef Q_OS_WINRT
@@ -115,6 +117,7 @@ bool QLibraryPrivate::load_sys()
 #ifndef Q_OS_WINRT
     SetErrorMode(oldmode);
 #endif
+    locker.relock();
     if (!hnd) {
         errorString = QLibrary::tr("Cannot load library %1: %2").arg(
                     QDir::toNativeSeparators(fileName), qt_error_string());